package cn.nr19.jian.token

import cn.nr19.jian.J2Utils
import cn.nr19.jian.Jian
import cn.nr19.jian.exception.ParserException
import cn.nr19.jian.factory.EONFactory
import cn.nr19.jian.factory.TokenFactory
import cn.nr19.jian.`object`.EON
import java.lang.StringBuilder
import java.util.LinkedHashMap

/**
 * 节点 值，最终值，无其他运算，
 * VAR、VARSELF、STR、NUM、BOOLEAM、EON、ARR
 */
open class NodeValue : Node() {
    override fun nodeType(): ENode = ENode.value
}


class StrNode(v: String) : NodeValue(){
    var value = v
    override fun toString(): String {
        return "\"${J2Utils.zy(value)}\""
    }
    override fun nodeType(): ENode =  ENode.str
}

// 数字
class NumNode(v : Number) : Node(){
    override fun nodeType(): ENode = ENode.num
    var value : Number = 0
    init {
        this.value = v
    }

    override fun toString(): String {
        return value.toString()
    }
}

// 逻辑
class BooleanNode : Node{
    override fun nodeType(): ENode = ENode.boolean
    var value : Boolean = false
    constructor(v : Boolean){
        this.value = v
    }
    constructor(v : String){
        this.value = v.equals("真") || v.equals("true",true)
    }

    override fun toString(): String {
        return if (value) "真" else "假"
    }
}

// 数组
class ARRNode : Node{

    constructor()
    constructor(ls : List<Node>){
        this.datas.addAll(ls)
    }
    constructor(str : String){
        str.trim().let { v->
            if (v.isEmpty()) return
            if (v.startsWith("[") && v.endsWith("]")){
                TokenFactory().startEON(v).let {
                    EONFactory.start2(it).let {
                        if (it is ARRNode){
                            datas.addAll(it.datas)
                        }
                    }
                }
            }else{
                throw ParserException("无法生成数组对象，并非数组文本 ${str}",0)
            }
        }


    }
    val datas = ArrayList<Node>()
    fun put(any : Node){
        datas.add(any)
    }
    fun add(n : Node){
        datas.add(n)
    }

    override fun nodeType(): ENode = ENode.arr

    override fun toString(): String {
        StringBuilder().let {
            it.append("[")
            if (datas.size > 0) {
                it.append(datas[0])
                for (i in 1 until datas.size){
                    it.append(",").append(datas[i])
                }
            }
            it.append("]")
            return it.toString()
        }
    }
}

/**
 * EON 和 EONNode 区别在于，EON 的 Value 接纳所有参数，而EonNode 仅支持 Jian的节点数据。
 * 两个最终 toString() 结果是一致的。 解析的文本也是一致的
 */
class EONNode : Node{
    constructor()
    // EON 中直接解析出节点
    constructor(code :String){
        EONFactory.start(code){

        }?.let {
            datas.putAll(it.datas)
        }
    }
    constructor(e : EON){
        e.keys.forEach {
            datas.put(it,Jian.toNode(e.get(it)!!))
        }
        
    }

    override fun nodeType(): ENode = ENode.eon
    val datas = LinkedHashMap<String,Node>()
    fun put(e : EONJNode){
        datas[e.name] = e.value!!
    }

    fun put(key : String,value : Node?){
        if (value == null) datas.remove(key)
        datas[key] = value!!
    }
    fun get(key : String) : Node?{
        return datas.get(key)
    }
    override fun toString(): String {
        StringBuilder().let {
            it.append("{")
            if (datas.size > 0) {
                datas.forEach {k->
                    if (!J2Utils.isKEYorNumber(k.key)){
                        it.append("\"").append(k.key).append("\"")
                    }else{
                        it.append(k.key)
                    }
                    it.append(":").append(k.value).append(",")

                }
                it.deleteCharAt(it.length - 1)
            }
            it.append("}")
            return it.toString()
        }
    }
    fun getEONObj(key : String) : EONNode?{
        val v = datas[key] ?: return null
        return if (v is EONNode) v
        else null
    }
    fun getArrayObj(key : String) : ARRNode?{
        val v = datas[key] ?: return null
        return if (v is ARRNode) v
        else null
    }
    fun getStr(key : String) : String?{
        val v = datas[key] ?: return null
        return if (v is StrNode) v.value
        else null
    }
    fun getInt(key : String) : Int?{
        val v = datas[key] ?: return null
        return if (v is NumNode) v.value.toInt()
        else null
    }


    // **************************************
    // ******** 方便操作、编辑的函数 ***********

    fun int(key: String,def : Int) : Int{
        get(key).let {
            if (it is NumNode) return Jian.toInt(it.value)
            else return def
        }
    }

    fun str(key: String,def : String) : String{
        get(key).let {
            if (it is StrNode) return it.value
            else return def
        }
    }
    fun boolean(key: String,def : Boolean) : Boolean{
        get(key).let {
            if (it is BooleanNode) return it.value
            else return def
        }
    }

}
class EONJNode : Node {
    override fun nodeType(): ENode = ENode.value
    // KEY : zhi;
    var name = ""
    var value: Node? = null

    constructor()
    constructor(name: String, value: Node) {
        this.name = name
        this.value = value
    }

    /**
     * token 必须为KEY
     */
    constructor(token: Token) {
        setStartToken(token)
        this.name = token.text
    }

    override fun toString(): String {
        return "$name:$value"
    }

    // 转为参数节点
    fun toParNode(): ParNode {
        ParNode().let { par ->
            par.name = name
            value?.let {
                if (it is StrNode) par.type = ParTypeNode(it.value)
            }
            return par
        }
    }
}

// 注释，换行
class PN(val value : String) : Node(){
    override fun nodeType(): ENode = ENode.pn
    override fun toString(): String {
        return value
    }

    override fun toStr(level: Int): String {
        return super.toStr(level)
    }
}
class NotesNode(v : String) : Node(){
    var value = v
    override fun nodeType(): ENode = ENode.notes

    override fun toString(): String {
        return "/* ${value} */"
    }


}

/**
 * KEY 没节点认领，就是变量
 */
class VarNode : Node{
    override fun nodeType(): ENode = ENode.gvar
    var name : String = ""

    // 编辑器用
    var type : ParTypeNode ?= null

    constructor(token: Token){
        this.name  = token.text
        setStartToken(token)
    }
    constructor(name : String,startPosition : Int = 0){
        this.name = name
        this.position = startPosition
    }

    override fun toString(): String {
        return name
    }
}


// 'xxx'
class E3Node : Node {
    var value : String = ""
    constructor(v : String){
        this.value = v
    }
    constructor(token: Token){
        this.value = token.text
        setStartToken(token)
    }
    override fun nodeType(): ENode = ENode.c_jian
    override fun toString(): String {
        return "<简>${value.replace("</简>","\\</简>")}</简>"
    }
}
class JsNode : Node {

    var value : String = ""
    constructor(v : String){
        this.value = v
    }
    constructor(token: Token){
        this.value = token.text
        setStartToken(token)
    }
    override fun nodeType(): ENode = ENode.c_js
    override fun toString(): String {
        return "<js>${value.replace("</js>","\\</js>")}</js>"
    }
}
class LayoutNode : Node {
    constructor()

    var code : String = ""
    constructor(t : String){
        this.code =t
    }
    constructor(token: Token){
        this.code = token.text
        setStartToken(token)
    }

    override fun nodeType(): ENode = ENode.c_layout

    override fun toString(): String {
        return "<布局>${code}</布局>"
    }
}
class E2Node : Node {
    var value : String = ""
    constructor(v : String){
        this.value = v
    }
    constructor(token: Token){
        setStartToken(token)
        this.value = token.text
    }
    override fun nodeType(): ENode = ENode.c_e2
    override fun toString(): String {
        return "<e2>${value.replace("</e2>","\\</e2>")}</e2>"
    }
}
class ExNode(token: Token) : Node() {
    // 应当中 code 中解析到 obj 的
    var obj : Node ?= null
    var code : String
    init {
        this.code = token.text
        setStartToken(token)
    }
    override fun nodeType(): ENode = ENode.c_ex
    override fun toStr(level: Int): String {
        return "<ex>" + code + "</ex>"
    }
}


